[SpringBoot] Beanとは一体何者なのか?
はじめに
Springフレームワークに馴染んだ後、SpringBootに触れた方はこのような疑問は持たれないのでしょうが、 僕のようにSpringを知らずにSpringBootを始める方も中にはいるのではないかと思い、僕が非常に悩んだBeanというものについて僕が現状知っていることを書いてみようと思います。
注) 間違っていること、説明が不足していることありましたらご指摘いただければ嬉しいです。
結論
間違いを恐れずに言えばBeanとは
@Beanと書いたメソッドでインスタンス化されたクラスがシングルトンクラスとしてDIコンテナに登録される。任意のクラスで@Autowiredで注入してアクセスできる。
と僕は理解しました。
わかりにくいですね。
僕も文章だけではうまく説明できないので、結論に至るまでの過程を書いていきます。
調査
まず@Beanというものについて調べた時に @Configurationと記述したクラス内のメソッドに@Beanを記述することで@Beanを定義することができ、任意のクラスで@Autowiredで注入することで定義したBeanを使うことができる。
ということで僕が最初に書いたコードがこんな感じです。
※@Scheduledは定期実行するためのアノテーションになります。興味のある方はこちらをどうぞ!
@Configuration public class CreateBean { @Bean public String getHoge(){ return "hoge"; } }
@Component public class BatchProcessing { @Autowired CreateBean createBean; @Scheduled(initialDelay = 3000, fixedDelay = 5000) public void initialDelay(){ System.out.println(createBean.getHoge()); } }
結果は
hoge hoge hoge hoge
試しに@Beanを消してビルドしてもエラーも出ず、同じ結果になります。
じゃあ結局Beanって何なんだ!!
アノテーションなくても動くじゃん!!
バカですいません。
@Beanの正しい使い方は以下のようになります。
public class Count { private int count; public int getCount(){ return count++; } }
このクラスは、呼ばれるたびに変数countをインクリメントして返すgetCount()メソッドと、インクリメントする変数countだけを持ったシンプルなクラスです。
@Configuration public class CreateBean { @Bean public Count getCount(){ return new Count(); } }
ここでCountクラスをDIコンテナに登録しています。
@Component public class BatchProcessing { @Autowired Count count; @Scheduled(initialDelay = 3000, fixedDelay = 5000) public void initialDelay(){ System.out.println(count.getCount()); } }
ここで登録したCountクラスを@Autowiredで注入しています。
0 1 2 3
メソッドに@Beanを記述するという言葉に引っ張られて、普通のStringやintを返すメソッドに@Beanを記述していましたが Stringやintを返すメソッドに@Beanをつけても何の意味もありません。
@Beanを記述したメソッドでインスタンス化したクラスを返して、DIコンテナに登録します。そして任意のクラスで@Autowiredで変数に注入して使うようです。
わかってしまえば簡単なことなのになぜ僕はあんな無駄な時間を。。
さらに
@Component public class BatchProcessing { @Autowired OuterBatchProcessing outerBatchProcessing; @Autowired Count count; @Scheduled(initialDelay = 3000, fixedDelay = 5000) public void initialDelay(){ System.out.println(count.getCount() + " : from BatchProcessing"); } @Scheduled(initialDelay = 5000, fixedDelay = 5000) public void OuterProcessing(){ outerBatchProcessing.execute(); } }
BatchProcessingクラスを少し直して
@Component public class OuterBatchProcessing { @Autowired private Count count; public void execute(){ System.out.println(count.getCount() + " : from OuterBatchProcessing"); } }
別のクラスからも登録しているBeanを使ってみます。
結果は
0 : from BatchProcessing 1 : from OuterBatchProcessing 2 : from BatchProcessing 3 : from OuterBatchProcessing 4 : from BatchProcessing 5 : from OuterBatchProcessing
@Beanで定義したクラスはデフォルトではシングルトンとしてDIコンテナに格納されるようですね。
最後に
Srpingに馴染んでいる方にとっては当たり前のことなんだろうなと思いながら、SpringBootから始めた僕のような迷い子がいるのではないかと思い書いてみました。 SpringBoot + Gradle の組み合わせで始めるとネットの情報は Spring + Maven の情報が多くわかりにくいので、今後もSpringBoot + Gradle の組み合わせで開発した時のことを書いていこうと思います。
参考
http://www.riem.nagoya-u.ac.jp/~ohta/etc/springboot-5.html